using System;
using System.Linq;
using Engine;
using Engine.Graphics;
using Engine.OldSerialization;

namespace RuthlessConquest {
    public class Satellite : Entity {
        public class Laser {
            public Point2 TargetPosition;

            public float TimeToLive = 0.45f;
        }

        public float Rotation;

        public int TargetAltitude;

        public int Index;

        public DynamicArray<Laser> Lasers = new();

        public DynamicArray<Body> TmpBodies = new();

        public DynamicArray<Planet> TmpPlanets = new();

        public DynamicArray<Ship> TmpShips = new();

        public Planet Planet { get; set; }

        public Point2 Position { get; set; }

        public int Altitude { get; set; }

        public bool IsEnabled {
            get {
                if (Planet != null) {
                    return Planet.Game.PlayersModule.FindPlayer(Planet.Faction)?.AreSatellitesEnabled ?? true;
                }
                return false;
            }
        }

        public Satellite() => TargetAltitude = 190;

        public Satellite(Planet planet, int altitude) : this() {
            Index = planet.Satellites.Count();
            Planet = planet;
            Altitude = altitude >= 0 ? altitude : TargetAltitude;
            if (planet.Satellites.Count() > 0) {
                Point2 point = planet.Satellites.First().Position - planet.Position;
                Position = planet.Position - point;
            }
            else {
                Position = planet.Position + new Point2(planet.Radius + Altitude, 0);
            }
        }

        public override void Serialize(InputArchive archive) {
            Planet = archive.Serialize<Planet>("Planet");
            Position = archive.Serialize<Point2>("Position");
            Altitude = archive.Serialize<int>("Altitude");
            Index = archive.Serialize<int>("Index");
        }

        public override void Serialize(OutputArchive archive) {
            archive.Serialize("Planet", Planet);
            archive.Serialize("Position", Position);
            archive.Serialize("Altitude", Altitude);
            archive.Serialize("Index", Index);
        }

        public void Step() {
            if (Planet == null) {
                return;
            }
            int num = 40 + PlanetsModule.Planets.IndexOf(Planet) % 11;
            if ((int)Planet.Faction % 2 == 0) {
                num = -num;
            }
            Point2 point = Position - Planet.Position;
            Position += new Point2(point.Y, -point.X) * num / 1000;
            Rotation += 0.07f * num * (1f / 60f);
            if (Altitude < TargetAltitude) {
                Altitude += MathUtils.Max((TargetAltitude - Altitude) / 20, 1);
            }
            else if (Altitude > TargetAltitude) {
                Altitude -= MathUtils.Max((Altitude - TargetAltitude) / 20, 1);
            }
            ClampToOrbit();
            if (IsEnabled) {
                int num2 = 33;
                int num3 = (MathUtils.Hash(PlanetsModule.Planets.IndexOf(Planet) + Index) % num2 + num2) % num2;
                if (StepModule.StepIndex % num2 == num3) {
                    Fire();
                }
            }
        }

        public void Draw(Color colorTransform) {
            if (Planet == null) {
                return;
            }
            FlatBatch2D flatBatch2D = CameraModule.PrimitivesRenderer.FlatBatch();
            foreach (Laser laser in Lasers) {
                Color ci = Color.White * MathUtils.Saturate(3.5f * laser.TimeToLive) * 1f;
                Color ci2 = Color.White * MathUtils.Saturate(3.5f * laser.TimeToLive) * 0.5f;
                DrawingUtils.QueueThickLine(
                    flatBatch2D,
                    new Vector2(Position),
                    new Vector2(laser.TargetPosition),
                    0f,
                    30f,
                    0f,
                    20f,
                    ci,
                    Color.Transparent,
                    ci2,
                    Color.Transparent
                );
                laser.TimeToLive -= Time.FrameDuration;
            }
            if (Lasers.Count > 0) {
                Lasers.RemoveAll(l => l.TimeToLive <= 0f);
            }
            Color color = IsEnabled ? Planet.GetColor(Planet.Faction) : Planet.GetColor(Faction.Neutral);
            Color color2 = Color.MultiplyColorOnly(color, 0.7f);
            flatBatch2D.QueueDisc(
                new Vector2(Position),
                new Vector2(35f),
                new Vector2(25f),
                0f,
                color2,
                Color.Transparent,
                5,
                Rotation,
                Rotation + (float)Math.PI * 2f
            );
            flatBatch2D.QueueDisc(
                new Vector2(Position),
                new Vector2(65f),
                new Vector2(35f),
                0f,
                color2,
                color2,
                5,
                Rotation,
                Rotation + (float)Math.PI * 2f
            );
            flatBatch2D.QueueDisc(
                new Vector2(Position),
                new Vector2(85f),
                new Vector2(65f),
                0f,
                color,
                color,
                5,
                Rotation,
                Rotation + (float)Math.PI * 2f
            );
            flatBatch2D.QueueDisc(
                new Vector2(Position),
                new Vector2(95f),
                new Vector2(85f),
                0f,
                Color.Transparent,
                color,
                5,
                Rotation,
                Rotation + (float)Math.PI * 2f
            );
        }

        public void Fire() {
            if (Planet == null) {
                return;
            }
            int num = 1750;
            int num2 = 250;
            int num3 = 250;
            DynamicArray<Ship> dynamicArray = new();
            for (int i = -num; i <= num; i += num3) {
                for (int j = -num; j <= num; j += num3) {
                    if (IntMath.LengthSquared(i, j) > num * num) {
                        continue;
                    }
                    int item = Position.X + i;
                    int item2 = Position.Y + j;
                    TmpBodies.Clear();
                    BodiesModule.QueryBodies((X: item, Y: item2), num2, TmpBodies, int.MaxValue);
                    if (TmpBodies.Count <= 0) {
                        continue;
                    }
                    TmpPlanets.Clear();
                    foreach (Body tmpBody in TmpBodies) {
                        if (tmpBody.Tag is Planet item3) {
                            TmpPlanets.Add(item3);
                        }
                    }
                    TmpShips.Clear();
                    foreach (Body tmpBody2 in TmpBodies) {
                        if (!(tmpBody2.Tag is Ship ship)
                            || ship.Faction == Planet.Faction
                            || ship.GiftToFaction == Planet.Faction
                            || (Planet.Faction == Faction.Neutral && !ship.Route.Contains(Planet))
                            || (ship.Faction == Faction.Neutral && !ship.Route.Any(p => p.Faction == Planet.Faction))) {
                            continue;
                        }
                        bool flag = false;
                        foreach (Planet tmpPlanet in TmpPlanets) {
                            if (IntMath.ApproxDistance(ship.Position, tmpPlanet.Position) <= ship.Body.GridRadius + tmpPlanet.Radius) {
                                flag = true;
                                break;
                            }
                        }
                        if (!flag) {
                            TmpShips.Add(ship);
                        }
                    }
                    if (TmpShips.Count > 0
                        && TmpShips.Count > dynamicArray.Count) {
                        dynamicArray.Clear();
                        dynamicArray.AddRange(TmpShips);
                    }
                }
            }
            if (dynamicArray.Count <= 0) {
                return;
            }
            Point2 zero = Point2.Zero;
            foreach (Ship item4 in dynamicArray) {
                zero += item4.Position;
            }
            zero /= dynamicArray.Count;
            Point2 position = dynamicArray.First().Position;
            foreach (Ship item5 in dynamicArray) {
                if (IntMath.DistanceSquared(item5.Position, zero) < IntMath.DistanceSquared(position, zero)) {
                    position = item5.Position;
                }
            }
            foreach (Ship item6 in dynamicArray) {
                int num4 = IntMath.ApproxDistance(position, item6.Position);
                int num5 = 100 * (num2 - num4) / num2;
                if (StepModule.Random.Int(100) < num5) {
                    item6.RemoveShip(true, 1000f * Vector2.Normalize(new Vector2(item6.Position - position)));
                }
            }
            Lasers.Add(new Laser { TargetPosition = position });
            _ = 1000f * Vector2.Normalize(new Vector2(position) - new Vector2(Position));
            AudioManager.PlaySound(Sounds.Laser, true, 0.4f);
        }

        public void ClampToOrbit() {
            if (Planet == null) {
                return;
            }
            int num = Planet.Radius + Altitude;
            if (num > 0) {
                Point2 point = Position - Planet.Position;
                int num2 = IntMath.Length(point);
                int num3 = 1000 * num2 / num;
                if (num3 > 0) {
                    point = point * 1000 / num3;
                    Position = Planet.Position + point;
                }
            }
        }

        public override void OnAdded() {
            Planet.Satellites.Add(this);
            Game.PlanetsModule.FactionOwnSatelliteCount[(int)Planet.Faction]++;
        }

        public override void OnRemoved() {
            Planet.Satellites.Remove(this);
            Game.PlanetsModule.FactionOwnSatelliteCount[(int)Planet.Faction]--;
        }
    }
}